#include "StdAfx.h"
#include "Sintactico.h"


Sintactico::Sintactico(void)
{
	this->lexico = new Lexico("code2.lpp");
	this->token_actual = lexico->getNextToken();

	this->tabla_de_tipos= new tabla_simbolos();
	this->tabla_de_variables = new tabla_simbolos();
	
	item_ts *Entero = new item_ts(new entero(),"ENTERO");
	item_ts *Booleano = new item_ts(new booleano(),"BOOLEANO");
	item_ts *Caracter = new item_ts(new caracter(),"CARACTER");
	item_ts *Real = new item_ts(new real(),"REAL");
	
	this->tabla_de_tipos->additem(Entero);
	this->tabla_de_tipos->additem(Booleano);
	this->tabla_de_tipos->additem(Caracter);
	this->tabla_de_tipos->additem(Real);

	
}

Sintactico::Sintactico(string dir){
	this->lexico = new Lexico(dir);
	this->token_actual = lexico->getNextToken();

	this->tabla_de_tipos= new tabla_simbolos();
	this->tabla_de_variables = new tabla_simbolos();
	
	item_ts *Entero = new item_ts(new entero(),"ENTERO");
	item_ts *Booleano = new item_ts(new booleano(),"BOOLEANO");
	item_ts *Caracter = new item_ts(new caracter(),"CARACTER");
	item_ts *Real = new item_ts(new real(),"REAL");
	
	this->tabla_de_tipos->additem(Entero);
	this->tabla_de_tipos->additem(Booleano);
	this->tabla_de_tipos->additem(Caracter);
	this->tabla_de_tipos->additem(Real);

}

Sintactico::~Sintactico(void)
{
}

void Sintactico::match(int tokentype){
	if(this->token_actual->getCod() == tokentype){
		this->token_actual = lexico->getNextToken();
	}else{
		stringstream out;
		
		out << "Error Sintactico: Se esperaba otro token: "<<this->tokentype.returntokenstring(tokentype)<<"; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
		throw  exception(out.str().c_str());
	}

}

Sentencia* Sintactico::S(){
	Sentencia* instrucciones  =PROGRAMAS();
	
	match(tokentype.fin_archivo);

	return instrucciones;
}

Sentencia* Sintactico::PROGRAMAS(){
	ENTER_PRI();
	REGISTRO_PRI();
	DECLARAR_PRI(this->tabla_de_variables);
	PROCEDIMIENTO_FUNCION();
	match(tokentype.revInicio);
	ENTER_PRI();
	Sentencia* instrucciones =INTRUCCIONES();
	ENTER_PRI();
	match(tokentype.revFin);
	ENTER_PRI();
	return instrucciones;
}

void Sintactico::ENTER(){
	match(tokentype.enter);
	ENTER_PRI();
}

void Sintactico::ENTER_PRI(){
	if(this->token_actual->getCod() == tokentype.enter){
		ENTER();
	}

}

void Sintactico::REGISTRO(){
	
	tabla_simbolos* tabla_registro = new tabla_simbolos();
	match(tokentype.revRegistro);
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);
	DECLARAR_PRI(tabla_registro);
	match(tokentype.revFin);
	match(tokentype.revRegistro);
	registro *Registro = new registro(tabla_registro);
	if(this->tabla_de_tipos->get(lexema)==0){
		this->tabla_de_tipos->additem(new item_ts(Registro,lexema));
	}else{
		stringstream out;
			out<<"Variable Ya Exite "<< lexema<<endl;
			throw exception(out.str().c_str());
	}
	

}

void Sintactico::REGISTRO_PRI(){
	if(this->token_actual->getCod()==tokentype.revRegistro){
		REGISTRO();
		ENTER();
		REGISTRO_PRI();
	}
}

void Sintactico::DECLARAR(tabla_simbolos *ts){

	tipo_ts* its = TIPORETORNO();
	vector<string> ids;
	ids = LISTAID(ids);
	for(int i=0;i<(int)ids.size();i++){
		if(ts->get(ids.at(i))==0 && this->tabla_de_tipos->get(ids.at(i))==0){
			ts->additem(new item_ts(its,ids.at(i)));
		}else{
			stringstream out;
			out<<"Variable Ya Exite "<<ids.at(i) <<endl;
			throw exception(out.str().c_str());
		}
	}
	
}

void Sintactico::DECLARAR_PRI(tabla_simbolos *ts){
	if(token_actual->getCod()==tokentype.revEntero || token_actual->getCod()==tokentype.revReal || token_actual->getCod()==tokentype.revCaracter|| token_actual->getCod()==tokentype.revCadena || token_actual->getCod()==tokentype.litIdentificador||token_actual->getCod()==tokentype.revBooleano || token_actual->getCod()==tokentype.revArreglo){
		DECLARAR(ts);
		ENTER();
		DECLARAR_PRI(ts);
	}else{
			if(this->token_actual->getCod()==tokentype.enter){
			match(tokentype.enter);
			DECLARAR_PRI(ts);
			}
		}
}

void Sintactico::PROCEDIMIENTO_FUNCION(){
	if(token_actual->getCod()==tokentype.revProcedimiento || token_actual->getCod()== tokentype.revFuncion){
		PROCEDIMIENTO_FUNCION_PRI();
		ENTER();
		PROCEDIMIENTO_FUNCION();
	}
}

void Sintactico::PROCEDIMIENTO_FUNCION_PRI(){
	if(token_actual->getCod()==tokentype.revProcedimiento){
		PROCEDIMIENTO();
	}else{
			FUNCION();
	}
}

void Sintactico::PROCEDIMIENTO(){
	
	tabla_simbolos* tabla_procedimiento = new tabla_simbolos();
	tabla_simbolos* tabla_params = new tabla_simbolos();
	tabla_simbolos* temp = new tabla_simbolos();
	
	match(tokentype.revProcedimiento);
	string lexema = token_actual->getLexema();
	lexema.append("&FP&");
	match(tokentype.litIdentificador);
	PARAMS(tabla_params);
	ENTER();
	DECLARAR_PRI(tabla_procedimiento);
	match(tokentype.revInicio);
	ENTER_PRI();
	Sentencia *intruccion = INTRUCCIONES();
	ENTER_PRI();
	match(tokentype.revFin);
	if(this->tabla_de_tipos->get(lexema)==0){
		int sizeP = tabla_params->getTable().size();
		int sizePr = tabla_procedimiento->getTable().size();
		if(sizeP>0&&sizePr>0){
			for(int i=0;i<sizeP;i++){
				for(int j=0;j<sizePr;j++){
					if(tabla_params->getTable().at(i)->getId().compare(tabla_procedimiento->getTable().at(j)->getId())==0){
					stringstream out;
						out<<"Variable No se Pueden Llamar igual que los Parametros"<<endl;
					throw exception(out.str().c_str());
				}
				}
				
			}
		}


		vector<item_ts*> allpro = this->tabla_de_variables->getALL(lexema);
		if(allpro.size()>0){
			for(int i=0;i<allpro.size();i++){
				procedimiento* item = (procedimiento*)allpro.at(i)->getTipo();
				int size = item->getParams()->getTable().size();
				int count = 0 ;
				if(size==tabla_params->getTable().size()){
					for(int j=0;j<size;j++){
						if(tabla_params->getTable().at(j)->getTipo()->is().compare(item->getParams()->getTable().at(j)->getTipo()->is())==0){
							count++;
						}

					}
					if(count == size){
							stringstream out;
							out<<"Ya existe sobrecarga de funcion o procedimiento "<<lexema<<endl;
							throw exception(out.str().c_str());
					}
				}
			}

		}


		
		procedimiento *Procedimiento = new procedimiento(tabla_params,tabla_procedimiento,intruccion);
		this->tabla_de_variables->additem(new item_ts(Procedimiento,lexema));
		for(int i=0;i<sizeP;i++){
			temp->additem(tabla_params->getTable().at(i));
		}
		for(int i=0;i<sizePr;i++){
			temp->additem(tabla_procedimiento->getTable().at(i));
		}
		for(int i=0;i<this->tabla_de_variables->getTable().size();i++){
			if(temp->get(this->tabla_de_variables->getTable().at(i)->getId())==0){
				temp->additem(this->tabla_de_variables->getTable().at(i));
			}
		}
		if(intruccion!=0){

		intruccion->validarSemantica(tabla_de_tipos,temp);
		}
		delete temp;

	}else{
		stringstream out;
		out<<"Variable Ya Exite "<<lexema<<endl;
		throw exception(out.str().c_str());
	}
	
}

void Sintactico::FUNCION(){

	tabla_simbolos* tabla_funcion = new tabla_simbolos();
	tabla_simbolos* tabla_params = new tabla_simbolos();
	tabla_simbolos* temp = new tabla_simbolos();
	match(tokentype.revFuncion);
	string lexema = token_actual->getLexema();
	lexema.append("&FP&");
	match(tokentype.litIdentificador);
	PARAMS(tabla_params);
	match(tokentype.pntDosPuntos);
	tipo_ts *tts = TIPORETORNO();
	ENTER();
	DECLARAR_PRI(tabla_funcion);
	match(tokentype.revInicio);
	ENTER_PRI();
	Sentencia *intruccion =INTRUCCIONES();
	ENTER_PRI();
	match(tokentype.revFin);
	if( this->tabla_de_tipos->get(lexema)==0){
		int sizeP = tabla_params->getTable().size();
		int sizePr = tabla_funcion->getTable().size();
		if(sizeP>0&&sizePr>0){
			for(int i=0;i<sizeP;i++){
				for(int j=0;j<sizePr;j++){
					if(tabla_params->getTable().at(i)->getId().compare(tabla_funcion->getTable().at(j)->getId())==0){
					stringstream out;
						out<<"Variable No se Pueden Llamar igual que los Parametros"<<endl;
					throw exception(out.str().c_str());
				}
				}
				
			}
		}

		vector<item_ts*> allpro = this->tabla_de_variables->getALL(lexema);
		if(allpro.size()>0){
			for(int i=0;i<allpro.size();i++){
				procedimiento* item = (procedimiento*)allpro.at(i)->getTipo();
				int size = item->getParams()->getTable().size();
				int count = 0 ;
				if(size==tabla_params->getTable().size()){
					for(int j=0;j<size;j++){
						if(tabla_params->getTable().at(j)->getTipo()->is().compare(item->getParams()->getTable().at(j)->getTipo()->is())==0){
							count++;
						}

					}
					if(count == size){
							stringstream out;
							out<<"Ya existe sobrecarga de funcion o procedimiento "<<lexema<<endl;
							throw exception(out.str().c_str());
					}
				}
			}

		}

		funcion *Funcion = new funcion(tabla_params,tts,tabla_funcion,intruccion);
		this->tabla_de_variables->additem(new item_ts(Funcion,lexema));
		for(int i=0;i<sizeP;i++){
			temp->additem(tabla_params->getTable().at(i));
		}
		for(int i=0;i<sizePr;i++){
			temp->additem(tabla_funcion->getTable().at(i));
		}
		for(int i=0;i<this->tabla_de_variables->getTable().size();i++){
			if(temp->get(this->tabla_de_variables->getTable().at(i)->getId())==0){
				temp->additem(this->tabla_de_variables->getTable().at(i));
			}
		}
		if(intruccion!=0){
			intruccion->SetReturn(tts);
		intruccion->validarSemantica(tabla_de_tipos,temp);
		}
		delete temp;
	}else{
		stringstream out;
		out<<"Variable Ya Exite "<<lexema<<endl;
		throw exception(out.str().c_str());
	}
	
}

tipo_ts* Sintactico::TIPODATO(){
	if(token_actual->getCod()==tokentype.revEntero){
		match(tokentype.revEntero);

		return this->tabla_de_tipos->get("ENTERO")->getTipo();
	}else{
		if(token_actual->getCod()==tokentype.revReal){
			match(tokentype.revReal);
			return this->tabla_de_tipos->get("REAL")->getTipo();
		}else{
			if(token_actual->getCod()==tokentype.revCaracter){
				match(tokentype.revCaracter);
				return this->tabla_de_tipos->get("CARACTER")->getTipo();
			}else{
				if(token_actual->getCod()==tokentype.revCadena){
					string lexema = "CADENA";
					match(tokentype.revCadena);
					match(tokentype.pntcorIzq);
					string litentero = token_actual->getLexema();
					match(tokentype.litNumeroEntero);
					match(tokentype.pntcorDer);
					lexema.append(litentero);
					item_ts *i_ts=this->tabla_de_tipos->get(lexema);
					if(i_ts==0){
						i_ts = new item_ts(new cadena(atoi( litentero.c_str()) ),lexema);
						this->tabla_de_tipos->additem(i_ts);
					}
					return i_ts->getTipo();

				}else{
					if(token_actual->getCod()==tokentype.revBooleano){
						match(tokentype.revBooleano);
						return this->tabla_de_tipos->get("BOOLEANO")->getTipo();
					}else{
						if(token_actual->getCod()==tokentype.litIdentificador){
							string lexema = token_actual->getLexema();
							match(tokentype.litIdentificador);
							item_ts *its = this->tabla_de_tipos->get(lexema);
							if(its!=0){
								return its->getTipo();
							}else{
								stringstream out;
								out <<"TIPO no existe"<<endl;
								throw  exception(out.str().c_str());
							}
						}else{
							stringstream out;
							out << "Error Sintactico: Se Esperaba Tipo de Dato; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea() ;
							throw  exception(out.str().c_str());
						}

					}

				}
			}
		}
	}
}

tipo_ts* Sintactico::ARREGLO(){

	vector<TipoDato*> index;
	match(tokentype.revArreglo);
	match(tokentype.pntcorIzq);
	index = DIMS(index);
	vector<int> dims;
	for(int i=0;i<(int)index.size();i++){
		dims.push_back(atoi( index.at(i)->getValor().c_str() ));
	}
	match(tokentype.pntcorDer);
	match(tokentype.revDe);
	tipo_ts *its = TIPODATO();

	return new arreglo(dims,its);
}

vector<TipoDato*> Sintactico::DIMS(vector<TipoDato*> index){
	TipoDato* tipodato = DIMS_2PRI();
	index.push_back(tipodato);
	index = DIMS_PRI(index);
	return index;
}

vector<TipoDato*> Sintactico::DIMS_PRI(vector<TipoDato*> index){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		return DIMS(index);
	}else{
		return index;
	}
}

TipoDato* Sintactico::DIMS_2PRI(){
	if(token_actual->getCod()==tokentype.litNumeroEntero){
		TipoDato *tipodato = new TipoDato();
		tipodato->setis(tokentype.litNumeroEntero);
		tipodato->setValor(token_actual->getLexema());
		match(tokentype.litNumeroEntero);
		return tipodato;

	}else{
		if(token_actual->getCod()==tokentype.litIdentificador){
			Variable *variable = new Variable(0);
			variable->setValor(token_actual->getLexema());
			match(tokentype.litIdentificador);
			return variable;
		}else{
							stringstream out;
							out << "Error Sintactico: Se esperaba una literal entera o Identificador; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
							throw  exception(out.str().c_str());
		}
	}

}

vector<string> Sintactico::LISTAID(vector<string> ids){
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);
	ids.push_back(lexema);
	return LISTAID_PRI(ids);
}

vector<string> Sintactico::LISTAID_PRI(vector<string> ids){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		ids = LISTAID(ids);
	}
	return ids;
}

vector<Expr*> Sintactico::EXPRS(vector<Expr*> expr){
	expr.push_back(EXPR());
	expr = EXPRS_PRI(expr);

	return expr;
}

vector<Expr*> Sintactico::EXPRS_PRI(vector<Expr*> expr){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		expr = EXPRS(expr);
		return expr;
	}
	return expr;
}

Expr* Sintactico::EXPR(){
	return R();
}

Expr* Sintactico::R(){
	
	return R_PRI(E());
}

Expr* Sintactico::R_PRI(Expr* E_){
	if(token_actual->getCod()==tokentype.oprMayor){
		match(tokentype.oprMayor);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprMayor);
		return expr;
		
	}
	if(token_actual->getCod()==tokentype.oprMayorIgual){
		match(tokentype.oprMayorIgual);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprMayorIgual);
		return expr;
	}
	if(token_actual->getCod()==tokentype.oprMenor){
		match(tokentype.oprMenor);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprMenor);
		return expr;
	}
	if(token_actual->getCod()==tokentype.oprMenorIgual){
		match(tokentype.oprMenorIgual);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprMenorIgual);
		return expr;
	}
	if(token_actual->getCod()==tokentype.oprIgual){
		match(tokentype.oprIgual);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprIgual);
		return expr;
	}
	if(token_actual->getCod()==tokentype.oprDist){
		match(tokentype.oprDist);
		ExprBinaria *expr = new ExprBinaria(E_,E());
		expr->setis(tokentype.oprDist);
		return expr;
	}
	return E_;
}

Expr* Sintactico::E(){
	return E_PRI(T());
}

Expr* Sintactico::E_PRI(Expr* T_){
	if(token_actual->getCod()==tokentype.oprSuma){
		match(tokentype.oprSuma);
		ExprBinaria *expr = new ExprBinaria(T_,T());
		expr->setis(tokentype.oprSuma);	
		return E_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.oprResta){
		match(tokentype.oprResta);
		ExprBinaria *expr = new ExprBinaria(T_,T());
		expr->setis(tokentype.oprResta);	
		return E_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.oprLogicoO){
		match(tokentype.oprLogicoO);
		ExprBinaria *expr = new ExprBinaria(T_,T());
		expr->setis(tokentype.oprLogicoO);	
		return E_PRI(expr);
	}
	return T_;

}

Expr* Sintactico::T(){
	
	return T_PRI(P());

}

Expr* Sintactico::T_PRI(Expr* P_){
	if(token_actual->getCod()==tokentype.oprMult){
		match(tokentype.oprMult);
		ExprBinaria *expr = new ExprBinaria(P_,P());
		expr->setis(tokentype.oprMult);
		return T_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.oprDiv){
		match(tokentype.oprDiv);
		ExprBinaria *expr = new ExprBinaria(P_,P());
		expr->setis(tokentype.oprDiv);
		return T_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.oprLogicoY){
		match(tokentype.oprLogicoY);
		ExprBinaria *expr = new ExprBinaria(P_,P());
		expr->setis(tokentype.oprLogicoY);
		return T_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.revMod){
		match(tokentype.revMod);
		ExprBinaria *expr = new ExprBinaria(P_,P());
		expr->setis(tokentype.revMod);
		return T_PRI(expr);
	}
	if(token_actual->getCod()==tokentype.revDiv){
		match(tokentype.revDiv);
		ExprBinaria *expr = new ExprBinaria(P_,P());
		expr->setis(tokentype.revDiv);
		return T_PRI(expr);
	}

	return P_;
}

Expr* Sintactico::P(){
	return P_PRI(F());
}

Expr* Sintactico::P_PRI(Expr* F_){
	if(token_actual->getCod()==tokentype.oprExpo){
		match(tokentype.oprExpo);
		ExprBinaria *expr = new ExprBinaria(F_,F());
		expr->setis(tokentype.oprExpo);		
		return P_PRI(expr);
	}
	return F_;
}

Expr* Sintactico::F(){
	if(token_actual->getCod()==tokentype.litIdentificador){
		Variable *sin = VARIABLE();
		return sin;
	}else{
		if(token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter){
			return LITERAL();
		}else{
			if(token_actual->getCod()==tokentype.pntparIzq){
				match(tokentype.pntparIzq);
				Expr* r =  R();
				match(tokentype.pntparDer);
				return r;
			}else{
				if(token_actual->getCod()==tokentype.revNo){
					match(tokentype.revNo);
					ExprUnary *exprunary = new ExprUnary(R());
					exprunary->setis(tokentype.revNo);
					return exprunary;
				}else{
					if(token_actual->getCod()==tokentype.oprResta){
						match(tokentype.oprResta);
						TipoDato *menosuno = new TipoDato();
						menosuno->setis(tokentype.litNumeroEntero);
						menosuno->setValor("-1");
						ExprBinaria * exprbinaria = new ExprBinaria(F(),menosuno);
						exprbinaria->setis(tokentype.oprMult);
						return exprbinaria;
					}else{
						stringstream out;
						out << "Error Sintactico: se esperaba  una varaible o una literal o parentesis; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
						throw  exception(out.str().c_str());
					}
				}

			}
		}
	}

}

TipoDato* Sintactico::LITERAL(){
	
	TipoDato *tipodato = new TipoDato();
	if(token_actual->getCod()==tokentype.litCadena){
		tipodato->setis(token_actual->getCod());
		tipodato->setValor(token_actual->getLexema());
		match(tokentype.litCadena);
		return tipodato;
	}else{
		if(token_actual->getCod()==tokentype.litNumeroReal){
			tipodato->setis(token_actual->getCod());
			tipodato->setValor(token_actual->getLexema());	
			match(tokentype.litNumeroReal);
			return tipodato;
		}else{
			if(token_actual->getCod()==tokentype.revFalso){
				tipodato->setis(token_actual->getCod());
				tipodato->setValor(token_actual->getLexema());
				match(tokentype.revFalso);
				return tipodato;
			}else{
				if(token_actual->getCod()==tokentype.revVerdadero){
					tipodato->setis(token_actual->getCod());
					tipodato->setValor(token_actual->getLexema());
					match(tokentype.revVerdadero);
					return tipodato;
				}else{
					if(token_actual->getCod()==tokentype.litNumeroEntero){
						tipodato->setis(token_actual->getCod());
						tipodato->setValor(token_actual->getLexema());
						match(tokentype.litNumeroEntero);
						return tipodato;
					}else{
						if(token_actual->getCod()==tokentype.litCaracter){
							tipodato->setis(token_actual->getCod());
							tipodato->setValor(token_actual->getLexema());
							match(tokentype.litCaracter);
							return tipodato;
						}else{
							stringstream out;
							out << "Error Sintactico: se esperaba  una  literal; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
							throw  exception(out.str().c_str());
						}
					}
				}
			}
		}
	}
	
}

vector<TipoDato*> Sintactico::LITERAL_PRI(vector<TipoDato*> tipodato){
	TipoDato *tipodato_ = LITERAL();
	tipodato.push_back(tipodato_);
	tipodato = LITERAL_2PRI(tipodato);
	return tipodato;
}

vector<TipoDato*> Sintactico::LITERAL_2PRI(vector<TipoDato*> tipodato){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		tipodato= LITERAL_PRI(tipodato);
		return tipodato;
	}else{
		return tipodato;
	}

}

Retorne* Sintactico::RETORNE(){
	match(tokentype.revRetorne);
	Expr *expr = EXPR();
	Retorne *retorne = new Retorne(0,expr);
	return retorne;
}

tipo_ts* Sintactico::TIPORETORNO(){
	if(token_actual->getCod()==tokentype.revEntero || token_actual->getCod()==tokentype.revReal || token_actual->getCod()==tokentype.revCaracter|| token_actual->getCod()==tokentype.revCadena || token_actual->getCod()==tokentype.litIdentificador||token_actual->getCod()==tokentype.revBooleano ){
		return TIPODATO();
	}else{
		return ARREGLO();
	}
}

Sentencia* Sintactico::INSTRCICLO(){
	if(token_actual->getCod()==tokentype.revPara){
		match(tokentype.revPara);
		Asignar *asignar_ = ASIGNAR();
		match(tokentype.revHasta);
		Expr *expr_= EXPR();
		match(tokentype.revHaga);
		ENTER_PRI();
		Sentencia *instrucciones_ = INTRUCCIONES();
		ENTER_PRI();
		match(tokentype.revFin);
		match(tokentype.revPara);
		Para *para = new Para(0,asignar_,expr_,instrucciones_);
		return para;

	}else{
		if(token_actual->getCod()==tokentype.revMientras){
			match(tokentype.revMientras);
			Expr *expr_=EXPR();
			match(tokentype.revHaga);
			ENTER_PRI();
			Sentencia *instrucciones_ =INTRUCCIONES();
			ENTER_PRI();
			match(tokentype.revFin);
			match(tokentype.revMientras);
			Mientras *mientras = new Mientras(0,expr_,instrucciones_);
			return mientras;
		}else{
			if(token_actual->getCod()==tokentype.revRepita){
				match(tokentype.revRepita);
				ENTER_PRI();
				Sentencia *instrucciones_ =INTRUCCIONES();
				ENTER_PRI();
				match(tokentype.revHasta);
				Expr *expr_= EXPR();
				Repita *repita = new Repita(0,expr_,instrucciones_);
				return repita;

			}else{
				stringstream out;
						out << "Error Sintactico: se esperaba un ciclo; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
						throw  exception(out.str().c_str());
			}
		}
	}
}

Sentencia* Sintactico::INSTRCONDICIONAL(){
	if(token_actual->getCod()==tokentype.revSi){
		match(tokentype.revSi);
		Expr *expr_ = EXPR();
		match(tokentype.revEntonces);
		ENTER_PRI();
		Sentencia* instrucciones_ = INTRUCCIONES();
		ENTER_PRI();
		Sentencia* sino = SINO();
		match(tokentype.revFin);
		match(tokentype.revSi);
		SI *si = new SI(0,expr_,instrucciones_,sino);
		return si;


	}else{
		if(token_actual->getCod()==tokentype.revCaso){
			match(tokentype.revCaso);
			Variable *variable = VARIABLE_PRI();
			ENTER();
			CasoList *casolist = CASO();
			
			Sentencia *intrucciones = FINCASO();
			
			Caso *caso = new Caso(0,variable,casolist,intrucciones);
			return caso;
		}else{
			stringstream out;
						out << "Error Sintactico: se esperaba un condicional; Token Actual: " <<token_actual->getLexema() <<" Columna: "<<token_actual->getColumna()<< " Linea:"<<token_actual->getLinea();
						throw  exception(out.str().c_str());
		}

	}
}

void Sintactico::PARAMS(tabla_simbolos* ts){
	if(token_actual->getCod()==tokentype.pntparIzq){
	match(tokentype.pntparIzq);
	PARAMS_PRI(ts);
	match(tokentype.pntparDer);
	}
}

void Sintactico::PARAMS_PRI(tabla_simbolos* ts){
	item_ts* its = PARAM_PRI();
	if(this->tabla_de_tipos->get(its->getId())==0 && ts->get(its->getId())==0){
		ts->additem(its);
	}else{
		stringstream out;
		out<<"Variable Ya Exite "<< its->getId()<<endl;
		throw exception(out.str().c_str());
	}
	PARAMS_2PRI(ts);
}

void Sintactico::PARAMS_2PRI(tabla_simbolos* ts){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		PARAMS_PRI(ts);
	}
}

item_ts* Sintactico::PARAM_PRI(){
	if(token_actual->getCod()==tokentype.revVar){
		match(tokentype.revVar);
		item_ts *its = PARAM();
		its->setVar(true);
		return its;

	}else{
		return PARAM();
	}
}

item_ts* Sintactico::PARAM(){
	tipo_ts* tts = TIPORETORNO();
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);

	return new item_ts(tts,lexema);
}

Escriba* Sintactico::ESCRIBA(){
	match(tokentype.revEscriba);
	vector<Expr*> expr;
	expr = EXPRS(expr);
	Escriba *escriba = new Escriba(0,expr);
	return escriba;
}

Llamar*  Sintactico::LLAMAR(){
	match(tokentype.revLlamar);
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);
	vector<Expr*> expr = LLAMAR_PRI();
	Llamar *llamar = new Llamar(0,expr,lexema);
	return llamar;
}

vector<Expr*> Sintactico::LLAMAR_PRI(){
	if(token_actual->getCod()==tokentype.pntparIzq){
		match(tokentype.pntparIzq);
		vector<Expr*> expr = LLAMAR_2PRI();
		match(tokentype.pntparDer);
		return expr;
	}else{
		vector<Expr*> expr;
		return expr ;
	}
}

vector<Expr*> Sintactico::LLAMAR_2PRI(){
	vector<Expr*> expr;
	if(token_actual->getCod()==tokentype.litIdentificador || token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter || token_actual->getCod()==tokentype.pntparIzq || token_actual->getCod()==tokentype.revNo || token_actual->getCod()==tokentype.oprResta){
		expr = EXPRS(expr);
		 
	}
		return expr;
	
}

Lea* Sintactico::LEA(){
	match(tokentype.revLea);
	vector<Variable*> variables;
	variables = LISTAVARIABLES(variables);
	Lea *lea = new Lea(0,variables);
	return lea;

}

vector<Variable*> Sintactico::LISTAVARIABLES(vector<Variable*> variables){
	variables.push_back(VARIABLE_PRI());
	variables = LISTAVARIABLES_PRI(variables);
	return variables;
}

vector<Variable*> Sintactico::LISTAVARIABLES_PRI(vector<Variable*> variables){
	if(token_actual->getCod()==tokentype.pntComa){
		match(tokentype.pntComa);
		return LISTAVARIABLES(variables);
	}else{
		return variables;
	}
}

Asignar* Sintactico::ASIGNAR(){
	Variable *variable = VARIABLE_PRI();
	match(tokentype.oprAsig);	
	Asignar *asignar = new Asignar(0,variable,EXPR());
	return asignar;
}

Variable* Sintactico::VARIABLE(){
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);
	Variable *variable = VARIABLE_4PRI();
	variable->setSig(VARIABLE_3PRI());
	variable->setValor(lexema);
	return variable;
}

Variable* Sintactico::VARIABLE_PRI(){
	string lexema = token_actual->getLexema();
	match(tokentype.litIdentificador);
	Variable *variable = VARIABLE_2PRI();
	variable->setSig(VARIABLE_3PRI());
	variable->setValor(lexema);
	return variable;
}

Variable* Sintactico::VARIABLE_2PRI(){
	Variable *variable;
	if(token_actual->getCod()==tokentype.pntcorIzq){
		match(tokentype.pntcorIzq);	
		vector<Expr*> index;		
		index = EXPRS(index);
		match(tokentype.pntcorDer);
		variable = new IndexVariable(0,index);
		return variable;
	}else{
		return variable = new Variable(0);
	}
}

Variable* Sintactico::VARIABLE_3PRI(){
	if(token_actual->getCod()==tokentype.pntPunto){
		match(tokentype.pntPunto);
		return VARIABLE_PRI();
	}else{
		return 0;
	}
}

Variable* Sintactico::VARIABLE_4PRI(){
	Variable *variable;
	if(token_actual->getCod()==tokentype.pntparIzq){
		match(tokentype.pntparIzq);
		vector<Expr*>exprs= LLAMAR_2PRI();
		match(tokentype.pntparDer);
		variable = new VariableFuncion(0,exprs);
		return variable;
	}
	if(token_actual->getCod()==tokentype.pntcorIzq){
		match(tokentype.pntcorIzq);
		vector<Expr*> index;		
		index = EXPRS(index);
		match(tokentype.pntcorDer);

		variable = new IndexVariable(0,index);
		return variable;
	}

	 return variable = new Variable(0);
}

Sentencia* Sintactico::SINO(){
	if(token_actual->getCod()==tokentype.revSino){
		match(tokentype.revSino);
		ENTER_PRI();
		Sentencia *sentencia = INTRUCCIONES();
		ENTER_PRI();
		return sentencia;
	}else{
		return 0;
	}
}

Sentencia* Sintactico::FINCASO(){
	Sentencia *instruccion = 0;
	if(token_actual->getCod()==tokentype.revSino){
		match(tokentype.revSino);
		match(tokentype.pntDosPuntos);
		ENTER_PRI();
		instruccion= INTRUCCIONES();
		ENTER_PRI();

	}
	match(tokentype.revFin);
	match(tokentype.revCaso);
	return instruccion;
}

CasoList* Sintactico::CASO(){
	vector<TipoDato*> tipodato;
	tipodato = LITERAL_PRI(tipodato);
	match(tokentype.pntDosPuntos);
	ENTER_PRI();
	Sentencia *instrucciones = INTRUCCIONES();
	ENTER_PRI();
	CasoList *casolist = new CasoList(0,tipodato,instrucciones);
	if(token_actual->getCod()==tokentype.litCadena || token_actual->getCod()==tokentype.litNumeroReal || token_actual->getCod()==tokentype.revFalso || token_actual->getCod()==tokentype.revVerdadero || token_actual->getCod()==tokentype.litNumeroEntero || token_actual->getCod()==tokentype.litCaracter){
		casolist->setNext(CASO());
		return casolist;
	}else{
		return casolist;
	}
}

Sentencia* Sintactico::INTRUCCIONES(){
		if(token_actual->getCod()==tokentype.litIdentificador || token_actual->getCod()==tokentype.revPara || token_actual->getCod()==tokentype.revMientras || token_actual->getCod()==tokentype.revRepita || token_actual->getCod()==tokentype.revSi || token_actual->getCod()==tokentype.revCaso || token_actual->getCod()==tokentype.revEscriba || token_actual->getCod()==tokentype.revRetorne || token_actual->getCod()==tokentype.revLlamar || token_actual->getCod()==tokentype.revLea || token_actual->getCod()==tokentype.enter  ){
		Sentencia *sentencia =INSTRUCCION();
		ENTER_PRI();
		sentencia->setNext( INTRUCCIONES());
		ENTER_PRI();
		return sentencia;
	}else{
		return 0;
		}
}

Sentencia* Sintactico::INSTRUCCION(){
	if(token_actual->getCod()==tokentype.litIdentificador){
		Asignar *asiganar=ASIGNAR();
		ENTER();
		return asiganar;
	}else{
		if(token_actual->getCod()==tokentype.revPara || token_actual->getCod()==tokentype.revMientras || token_actual->getCod()==tokentype.revRepita){
			Sentencia *sentencia = INSTRCICLO();
			ENTER();
			return sentencia;
		}else{
			if(token_actual->getCod()==tokentype.revSi || token_actual->getCod()==tokentype.revCaso){
				Sentencia *sentencia = INSTRCONDICIONAL();
				ENTER();
				return sentencia;
			}else{
				if(token_actual->getCod()==tokentype.revEscriba){
					Escriba *escriba = ESCRIBA();
					ENTER();
					return escriba;
				}else{
					if(token_actual->getCod()==tokentype.revRetorne ){
						Retorne *retorne = RETORNE();
						ENTER();
						return retorne;
					}else{
						if(token_actual->getCod()==tokentype.revLlamar){
							Llamar *llamar =LLAMAR();
							ENTER();
							return llamar;
						}else{
							if(token_actual->getCod()==tokentype.revLea){
								Lea* lea =LEA();
								ENTER();
								return lea;
							}else{
								return 0;
							}
						}
					}
				}
			}
		}
	}
}

void Sintactico::print(Sentencia *sente){
	cout<<sente->is()<<endl;
	Asignar *asi = (Asignar*)sente;
	cout<<asi->getExpr()->is()<<endl;
	cout<<asi->getVariable()->is()<<endl;
	
}